/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.frames;

import ore.PositionVelocity;
import ore.Transform;
import ore.errors.OrekitException;
import ore.propagation.Propagator;
import ore.time.AbsoluteDate;

import org.apache.commons.math.geometry.Rotation;
import org.apache.commons.math.geometry.Vector3D;

/**
 * Class for frames moving with an orbiting satellite.
 * 
 * There are two main local orbital frames:
 * 
 * <ul>
 * 
 *   <li> The (t, n, w) frame has its X axis along velocity
 *   (tangential), its Z axis along orbital momentum and its Y axis
 *   completes the right-handed trihedra (it is roughly pointing
 *   towards the central body). </li>
 * 
 *   <li> The (q, s, w) frame has its X axis along position (radial),
 *   its Z axis along orbital momentum and its Y axis completes the
 *   right-handed trihedra (it is roughly along velocity). </li>
 * 
 * </ul>
 * 
 * @author Luc Maisonobe
 */
public class LocalOrbitalFrame
    extends ore.Frame
{
    /** 
     * List of supported frames types.
     */
    public enum LOFType {
        /**
         * Constant for TNW frame (X axis aligned with velocity).
         */
        TNW,
        /**
         * Constant for QSW frame (X axis aligned with position).
         */
        QSW
    }


    /** 
     * Frame type.
     */
    public final LOFType type;

    /** 
     * Propagator used to compute frame motion.
     */
    public final Propagator propagator;


    /** 
     * @param parent parent frame (must be non-null)
     * @param type frame type
     * @param propagator propagator used to compute frame motion
     * @param name name of the frame
     * 
     * @exception IllegalArgumentException if the parent frame is null
     */
    public LocalOrbitalFrame(ore.Frame parent, LOFType type,
                             Propagator propagator, String name)
        throws IllegalArgumentException
    {
        super(parent, Transform.IDENTITY, name);
        this.type       = type;
        this.propagator = propagator;
    }


    /**
     * {@inheritDoc}
     */
    protected void updateFrame(AbsoluteDate date)
        throws OrekitException
    {
        /*
         * Get position/velocity with respect to parent frame
         */
        PositionVelocity pv = propagator.propagate(date).getPositionVelocity(getParent());
        Vector3D p = pv.getPosition();
        Vector3D v = pv.getVelocity();
        Vector3D momentum = Vector3D.crossProduct(p, v);
        /*
         * Compute the translation part of the transform
         */
        Transform translation = new Transform(p.negate(), v.negate());
        /*
         * Compute the rotation part of the transform
         */
        Transform rotation =
            new Transform(new Rotation((type == LOFType.TNW) ? v : p, momentum,
                                        Vector3D.PLUS_I, Vector3D.PLUS_K),
                          new Vector3D(1.0 / p.getNormSq(), momentum));

        /*
         * Update the frame defining transform
         */
        this.setTransform(new Transform(translation, rotation));
    }
}
